#include "Actor.h"

namespace SEngine
{
    Actor::Actor(Scene &scene)
        : m_scene(scene) 
    {
        AddComponentSignal.AddSlot([this] (IComponent& comp) { SignalManager::OnAddComponent(comp); return SlotState::Keep; });
        RemoveComponentSignal.AddSlot([this] (IComponent& comp) { SignalManager::OnRemoveComponent(comp); return SlotState::Keep; });
    }

    Actor::~Actor()
    {
    }

    void Actor::SetParent(Actor & parent)
    {
        if (this == &parent) {
            return;
        }
        parent.m_children.emplace_back(this->shared_from_this());
        this->m_parent = &parent;
    }

    void Actor::AddChild(Actor & child)
    {
        child.SetParent(*this);
    }

    void Actor::RemoveChild(Actor &child)
    {
        m_children.erase(std::remove_if(
            m_children.begin(),
            m_children.end(),
            [&](std::weak_ptr<Actor> & elem) {
                if (elem.lock().get() == &child) {
                    child.m_parent = std::nullopt;
                    return true;
                }
                return false;
            }
        ), m_children.end());
    }

    void Actor::RemoveParent()
    {
        if (m_parent) {
            m_parent.value()->RemoveChild(*this);
        }
    }

    void Actor::ClearChildren()
    {
        for (auto & child : m_children) {
            if (!child.expired()) {
                child.lock()->m_parent = std::nullopt;
            }
        }
        m_children.clear();
    }

    void Actor::BeforeUpdate()
    {
        for (auto && [_, comp] : m_components) {
            if (comp->m_enabled) {
                comp->BeforeUpdate();
            }
        }
    }

    void Actor::OnUpdate(int delta)
    {
        for (auto && [_, comp] : m_components) {
            if (comp->m_enabled) {
                comp->OnUpdate(delta);
            }
        }
    }

    void Actor::AfterUpdate()
    {
        for (auto && [_, comp] : m_components) {
            if (comp->m_enabled) {
                comp->AfterUpdate();
            }
        }
    }

    void Actor::ForeachChildren(std::function<void(Actor &)> &&fn)
    {
        m_children.erase(
            std::remove_if(
                m_children.begin(),
                m_children.end(),
                [&fn](std::weak_ptr<Actor> & elem) {
                    if (!elem.expired()) {
                        fn(*elem.lock());
                    }
                    return elem.expired();
                }
            ), m_children.end()
        );
    }

    void Actor::ClearComponents()
    {
        for (auto && [_, comp] : m_components) {
            RemoveComponentSignal.Invoke(*comp);
        }
        m_components.clear();
    }

} // namespace SEngine

